/* $RCSFile: CrmInstaller.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/Helpers/CrmInstaller.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:28  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Globalization;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Reflection;
using System.Web;
using System.Xml;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using AddonNice.UI;
using AddonNice.Settings;
using AddonNice.UI.WebControls;
using AddonNice.Security;
using AddonNice.Configuration;
using AddonNice.Diagnostics;
using AddonNice.Core;

using AddonNice.CRMWrapper;

using Trace2    =   System.Diagnostics.Trace;
using Path2     =   AddonNice.Settings.Path;

namespace AddonNice.Helpers
{

    public class CrmInstallException : Exception
    {
        public CrmInstallException(string msg)
            : base(msg)
        {}

        public CrmInstallException(string msg,Exception inner)
            : base(msg,inner)
        {}
    }
    
    
    /// <summary>
	/// PackageInstall incapsulates all the logic for install packages on portal
	/// </summary>
	public class CrmInstaller
	{
        public bool fatalErr                        =   false;
        public string lastError                     =   string.Empty;
        public int nbInstalled                      =   0;
        CrmDB CrmManDB                              =   new CrmDB();
        public DBCrmServer srvObj                   =   null;
        Hashtable StateSaver                        =   new Hashtable();
        public ArrayList errors                     =   new ArrayList();
        public ProgressDelegate SetUpdateProgress   =   null;
        public ProgressSetTotalSteps SetTotSteps    =   null;
        public string DefaultCrmBackupPath          =   string.Empty;
        public CrmWrapper4 newWrapper               =   null;
        public List<string> ForbiddenPackages       =   new List<string>();
        public bool ShouldBackup                    =   true;
        public bool ShouldPublishCustom             =   true;
        public bool ShouldPublishSiteMap            =   true;
        public bool ShouldPublishISV                =   true;
        string CurrentPackageName                   =   string.Empty;
        ///  store internal necessary elements to complete a full entities install
        internal class InstallPack
        {
            public DBCrmEntity EntObj;
            public DynEntity dynEnt;
            public ICrmInstaller Installer;
            public bool installed   =   false;
        }

        Dictionary<string,InstallPack> Installers =   new Dictionary<string,InstallPack>();


        public CrmInstaller(string packageName,CRMWrapperBase w,bool backupCustom,bool publishOnEnd,ProgressDelegate f,ProgressSetTotalSteps setTotSteps)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller Ctor with Wrapper BEG packageName: {0}, backupCustom: {1}, publishOnEnd: {2}.",
                    packageName,backupCustom,publishOnEnd),InstallTraceSwitch.Sw.Info);
            newWrapper              =   w as CrmWrapper4;
            CurrentPackageName      =   packageName;
            DefaultCrmBackupPath    =   newWrapper.CrmBackupFolder;
            ShouldBackup            =   backupCustom;
            ShouldPublishCustom     =   publishOnEnd;
            SetUpdateProgress       =   f;
            SetTotSteps             =   setTotSteps;
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine("[V]CrmInstaller Ctor END.",InstallTraceSwitch.Sw.Info);
        }

        public CrmInstaller(string CrmBackupPath,List<string> FPackages,ProgressDelegate f,ProgressSetTotalSteps setTotSteps)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller Ctor BEG CrmBackupPath: {0}.",CrmBackupPath),InstallTraceSwitch.Sw.Info);
            SetUpdateProgress       =   f;
            SetTotSteps             =   setTotSteps;
            DefaultCrmBackupPath    =   CrmBackupPath;
            ForbiddenPackages       =   FPackages;
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine("[V]CrmInstaller Ctor END.",InstallTraceSwitch.Sw.Info);
        }

        public bool PreInstall()
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PreInstall BEG ShouldBackup: {0}.",ShouldBackup),InstallTraceSwitch.Sw.Info);
            // Make a backup of all customizations before installing modules
            bool ret                =   (ShouldBackup) ? newWrapper.Util.BackupCustomizations():true;
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PreInstall Backup Customizations success: {0}.",ret),InstallTraceSwitch.Sw.Info);
            // failed, we can't continue without backup
            if (!ret)
            {
                string msg          =   "[E]CrmInstaller PreInstall BackupCustomizations failed, stopping install.";
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("INSTALLCRM_BACKUPCUSTOMERR","Preliminary customization backup failed, stopping install");
                throw new CrmInstallException(msg);

            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PreInstall END ret: {0}.",ret),InstallTraceSwitch.Sw.Info);
            return ret;
        }
        
        public bool PostInstall()
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PostInstall BEG ShouldPublishCustom: {0}.",ShouldPublishCustom),InstallTraceSwitch.Sw.Info);
            bool ret                =   (ShouldPublishCustom) ? newWrapper.Util.PublishAll():true;
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PostInstall PublishAll Customizations success: {0}.",ret),InstallTraceSwitch.Sw.Info);
            // failed, we can't continue without backup
            if (!ret)
            {
                string msg          =   "[E]CrmInstaller PostInstall PublishAll failed, stopping install.";
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("INSTALLCRM_PUBLISHERR","PublishAll failed, stopping install");
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller PostInstall END ret: {0}.",ret),InstallTraceSwitch.Sw.Info);
            return ret;
        }
        
        /// <summary>
        /// This call will insert the CRM Server in DB, then install all  custom entities
        /// </summary>
        public void CreateCrmServer(DBCrmServer newSrv)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller CreateCrmServer BEG FriendlyName: {0}", newSrv.FriendlyName),InstallTraceSwitch.Sw.Info);
            srvObj                  =   newSrv;
            string title            =   LocalizeHelper.Localize("INSTALLCRM_CREATECRMSRV","Creating Crm Server in DB");
            SetUpdateProgress(title,1);
            try
            {
                srvObj.CrmServerId  =   CrmManDB.AddCrmServer(srvObj.FriendlyName,srvObj.CrmVersion,srvObj.UsePreAuthenticate,
                                                            srvObj.Organization,srvObj.AuthenticationType,srvObj.DiscoServer,srvObj.DiscoServerPort,string.Empty,
                                                            srvObj.ServiceAccount,srvObj.ServicePassword,srvObj.ServiceDomain,
                                                            srvObj.PrivAccount,srvObj.PrivPassword,srvObj.PrivDomain,
                                                            srvObj.DefaultAccount,srvObj.DefaultPassword,srvObj.DefaultDomain,srvObj.AdminRoleName);

                InstallCrmServer();
            }
            catch (Exception ex)
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller CreateCmServer FriendlyName: {0}, ex: {1}", srvObj.FriendlyName, ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( "[V]CrmInstaller CreateCrmServer END.",InstallTraceSwitch.Sw.Info);
         }

        /// <summary>
        /// Used when DBCrmServer is not setup by a CreateCrmServer
        /// </summary>
        public void InstallCrmServer(int CrmServerId)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer BEG CrmServerId: {0}", CrmServerId),InstallTraceSwitch.Sw.Info);
            srvObj                  =   CrmManDB.GetCrmServerObj(CrmServerId);
            InstallCrmServer();
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer END CrmServerId: {0}", CrmServerId),InstallTraceSwitch.Sw.Info);
        }
        
        void BuildInstallLst(List<string> InstallLst,string key)
        {
            if ( InstallLst.Contains(key)  )
                return;
            DynEntity dyn           =   Installers[key].dynEnt;
            if ( !dyn.DependsFromOtherEntities )
                InstallLst.Add(key);
            else
            {
                foreach(string precshem in dyn.DependsFrom.Values)
                {
                    if ( !InstallLst.Contains(precshem) && Installers.ContainsKey(precshem) )
                    {
                        BuildInstallLst(InstallLst,precshem);
                    }
                }
                InstallLst.Add(key);
            }
        }
        
        /// <summary>
        /// Install all the portal declared custom entities in this crm server
        /// Existing entities are not recreated
        /// </summary>
        public void InstallCrmServer()
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer BEG srvObj null: {0}", ( srvObj == null )),InstallTraceSwitch.Sw.Info);
            try
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer Organization: {0}, Wrapper created: {1}", 
                        srvObj.Organization,(newWrapper != null)),InstallTraceSwitch.Sw.Info);
                string title            =   string.Empty;
                if ( newWrapper == null )
                {
                    title               =   LocalizeHelper.Localize("INSTALLCRM_STARTWRAPPER","Starting wrapper");
                    SetUpdateProgress(title,1);
                    if (InstallTraceSwitch.Sw.TraceVerbose)
                        Trace2.WriteLine( "[V]CrmInstaller InstallCrmServer starting wrapper.",InstallTraceSwitch.Sw.Info);
                    newWrapper          =   new CrmWrapper4(srvObj.Organization,srvObj.DiscoServer,srvObj.DiscoServerPort,(ADNAuthenticationType)srvObj.AuthenticationType,
                                                    srvObj.ServiceAccount,srvObj.ServicePassword,srvObj.ServiceDomain,srvObj.DefaultAccount,srvObj.DefaultPassword,srvObj.DefaultDomain, 
                                                    srvObj.PrivAccount,srvObj.PrivPassword,srvObj.PrivDomain,srvObj.UsePreAuthenticate);
                    newWrapper.CrmBackupFolder  =   DefaultCrmBackupPath;
                    if (InstallTraceSwitch.Sw.TraceVerbose)
                        Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer wrapper initializing UsePreAuthenticate: {0}.",srvObj.UsePreAuthenticate),InstallTraceSwitch.Sw.Info);
                    newWrapper.Initialize(srvObj.UsePreAuthenticate);
                }
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller InstallCrmServer wrapper initialized.",InstallTraceSwitch.Sw.Info);
                // backup entities if necessary, stop if unable to backup
                if ( !PreInstall() )
                {
                    return;
                }
                
                title                       =   LocalizeHelper.Localize("INSTALLCRM_LOADINGCUSTOM","Installing custom entities.");
                SetUpdateProgress(title,1);
                
                // Read entities installed
                DataTable TbEntities        =   CrmManDB.GetAllCrmEntityTb();
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer wrapper initialized TbEntities.Rows: {0}.",TbEntities.Rows.Count),InstallTraceSwitch.Sw.Info);
                SetTotSteps(2*TbEntities.Rows.Count+10,1);
                // Prepare the install list
                foreach ( DataRow rw in TbEntities.Rows )
                {
                    DBCrmEntity entObj      =   new DBCrmEntity(rw);
                    if ( ForbiddenPackages.Contains(entObj.PackageName) || ( ( CurrentPackageName != string.Empty ) && (CurrentPackageName != entObj.PackageName) ))
                    {
                        if ( InstallTraceSwitch.Sw.TraceVerbose )
                            Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmServer Excluded PackageName: {0}, Entity: {1}.",
                                entObj.PackageName,entObj.SchemaName),InstallTraceSwitch.Sw.Info);
                        continue;
                    }
                    bool existInServer      =   CrmManDB.ExistCrmServerEntity(entObj.EntityId,srvObj.CrmServerId);
                    Prepare2InstallEntity(entObj,srvObj.CrmServerId,existInServer); // we add in the installer list even if already there, we must be able to upgrade UI
                }
                // Create the install list respecting the dependencies
                List<string> BuildLst     =   new List<string>();
                foreach ( string key in Installers.Keys )
                {
                    BuildInstallLst(BuildLst,key);
                }
                // Build entities respecting the order
                foreach ( string key in BuildLst )
                {
                    if ( !Installers[key].installed ) // if already installed in server, we do not reintsall fo speed reasons
                        InstallEntityInCrmServer(key,srvObj.CrmServerId,false);
                }
                // publish all if ShouldPublishCustom set
                PostInstall();
            }
            catch(CancelProgressException )
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller InstallCrmServer install cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError                                       =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
            catch(CrmInstallException)
            {
                throw;
            }
            catch (Exception ex)
            {
                string msg  =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallCrmServer ex: {0}", ex);
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace2.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine("[V]CrmInstaller InstallCrmServer END.",InstallTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Called to update the entity Custom in Crm Server
        /// </summary>
        public bool UpdateEntity(DBCrmEntity entObj,int CrmServerId)
        {
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller UpdateEntity BEG SchemaName: {0}, CrmServerId: {1}", 
                    entObj.SchemaName,CrmServerId),InstallTraceSwitch.Sw.Info);
            bool ret                    =   true;
            try
            {
                srvObj                  =   CrmManDB.GetCrmServerObj(CrmServerId);
                ICrmInstaller installer =   null;
                // Entity must be already there (else do full install )
                if ( CrmManDB.ExistCrmServerEntity(entObj.EntityId,srvObj.CrmServerId) )
                {
                    string title        =   string.Empty;
                    if ( newWrapper == null )
                    {
                        title           =   LocalizeHelper.Localize("INSTALLCRM_STARTWRAPPER","Starting wrapper");
                        SetUpdateProgress(title,1);
                        if (InstallTraceSwitch.Sw.TraceVerbose)
                            Trace2.WriteLine( "[V]CrmInstaller InstallCrmServer UpdateEntity wrapper.",InstallTraceSwitch.Sw.Info);
                        newWrapper      =   new CrmWrapper4(srvObj.Organization,srvObj.DiscoServer,srvObj.DiscoServerPort,(ADNAuthenticationType)srvObj.AuthenticationType,
                                                        srvObj.ServiceAccount,srvObj.ServicePassword,srvObj.ServiceDomain,srvObj.DefaultAccount,srvObj.DefaultPassword,srvObj.DefaultDomain, 
                                                        srvObj.PrivAccount,srvObj.PrivPassword,srvObj.PrivDomain,srvObj.UsePreAuthenticate);
                        newWrapper.CrmBackupFolder  =   DefaultCrmBackupPath;
                        if (InstallTraceSwitch.Sw.TraceVerbose)
                            Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller UpdateEntity wrapper initializing UsePreAuthenticate: {0}.",srvObj.UsePreAuthenticate),InstallTraceSwitch.Sw.Info);
                        newWrapper.Initialize(srvObj.UsePreAuthenticate);
                    }
                    if (InstallTraceSwitch.Sw.TraceVerbose)
                        Trace2.WriteLine( "[V]CrmInstaller UpdateEntity wrapper initialized.",InstallTraceSwitch.Sw.Info);
                    ret                 =   PreInstall();
                    if ( ret )
                    {
                        installer       =   Prepare2InstallEntity(entObj,CrmServerId,true);
                        InstallEntityInCrmServer(entObj.SchemaName,srvObj.CrmServerId,true);
                        // publish all if ShouldPublishCustom set
                        ret             =   PostInstall();
                    }
                }
            }
            catch(CancelProgressException )
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller UpdateEntity install cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError               =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
            catch(CrmInstallException)
            {
                throw;
            }
            catch (Exception ex)
            {
                string msg  =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller UpdateEntity ex: {0}", ex);
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace2.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine("[V]CrmInstaller UpdateEntity END.",InstallTraceSwitch.Sw.Info);
            return ret;
        }
        
        public ICrmInstaller Prepare2InstallEntity(DBCrmEntity entObj,int CrmServerId,bool existsinServer)
        {
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller Prepare2InstallEntity BEG SchemaName: {0}, CrmServerId: {1}", 
                    entObj.SchemaName,CrmServerId),InstallTraceSwitch.Sw.Info);
            ICrmInstaller installer  =   LoadEntityAssembly(entObj.InitClass,entObj.LoadAssembly);
            Prepare2InstallEntity(entObj,CrmServerId,installer,existsinServer);
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine("[V]CrmInstaller Prepare2InstallEntity END.",InstallTraceSwitch.Sw.Info);
            return installer;
        }

        /// <summary>
        /// Prepare the install for a new Addon Nice custom entity:do only the CrmServer part, no iframe or Form customization
        /// </summary>
		public void Prepare2InstallEntity(DBCrmEntity entObj,int CrmServerId,ICrmInstaller installer,bool existsinServer)
		{
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller Prepare2InstallEntity BEG SchemaName: {0}", entObj.SchemaName),InstallTraceSwitch.Sw.Info);

            int cnt                                     =   0;
            try
            {
                string fmt                              =   LocalizeHelper.Localize("INSTALLCRM_PREPARINGINST","Preparing install for {0}");
                string title                            =   string.Format(fmt,entObj.FriendlyName);
                SetUpdateProgress(title,1);
                DynEntity dyn                           =   installer.NewEntity(entObj.SchemaName,newWrapper);
                Installers.Add(entObj.SchemaName,new InstallPack { Installer = installer,dynEnt = dyn,EntObj = entObj, installed=existsinServer });
                cnt++;
                if ( InstallTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallEntity HasBuilder: {0}", dyn.HasBuilder),InstallTraceSwitch.Sw.Info);
            }
            catch(CancelProgressException )
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller Prepare2InstallEntity cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
            catch (Exception ex)
            {
                string msg                              =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallEntityInCrmServer ex: {0}", ex);
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace2.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                string fmt                              =   LocalizeHelper.Localize("INSTALLCRM_PREPAREENTITYERR","Error preparing install for Entity; {0}");
                lastError                               =   string.Format(fmt,entObj.SchemaName);
                throw new CrmInstallException(msg,ex);
            }
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller Prepare2InstallEntity END Count: {0}", cnt),InstallTraceSwitch.Sw.Info);
		}

        /// <summary>
        /// Install a new Addon Nice custom entity: do only the CrmServer part, no iframe or Form customization
        /// </summary>
		public void InstallEntityInCrmServer(string SchemaName,int CrmServerId,bool entityExist)
		{
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallEntityInCrmServer BEG SchemaName: {0}, Installers.ContainsKey: {1}", 
                    SchemaName,Installers.ContainsKey(SchemaName) ),InstallTraceSwitch.Sw.Info);
            if ( !Installers.ContainsKey(SchemaName) )
                return;
            InstallPack Pck                             =   Installers[SchemaName]; 
            ICrmInstaller installer                     =   Pck.Installer;
            DBCrmEntity entObj                          =   Pck.EntObj;
            DynEntity dyn                               =   Pck.dynEnt;
            int cnt                                     =   0;
            try
            {
                string fmt                              =   LocalizeHelper.Localize("INSTALLCRM_INSTALLING","Installing {0}");
                string title                            =   string.Format(fmt,entObj.FriendlyName);
                SetUpdateProgress(title,1);
                if ( InstallTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallEntity HasBuilder: {0}", dyn.HasBuilder),InstallTraceSwitch.Sw.Info);
                if ( dyn.HasBuilder )
                {
                    List<MetaDataBuilder> builderLst    =   dyn.Builder;
                    foreach ( MetaDataBuilder builder in builderLst )
                    {
                        builder.Backup                  =   false; // we have already backuped all
                        builder.Build(newWrapper,dyn.shouldCreateEntity,!ShouldPublishCustom); // publish each created entity if a general publish is not done after
                    }
                    nbInstalled++;
                }
                Pck.installed                           =   true;
                if ( entityExist )
                        CrmManDB.UpdateCrmServerEntity(entObj.EntityId,CrmServerId,entObj.EntityVersion);
                else    CrmManDB.AddCrmServerEntity(entObj.EntityId,CrmServerId,entObj.EntityVersion);
                cnt++;
            }
            catch(CancelProgressException )
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller InstallEntity install cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
            catch (Exception ex)
            {
                string msg                              =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallEntityInCrmServer ex: {0}", ex);
                if (InstallTraceSwitch.Sw.TraceError)
                    Trace2.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                string fmt                              =   LocalizeHelper.Localize("INSTALLCRM_ENTITYERR","Error installing Entity; {0}");
                lastError                               =   string.Format(fmt,entObj.SchemaName);
                throw new CrmInstallException(msg,ex);
            }
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallEntityInCrmServer END Count: {0}", cnt),InstallTraceSwitch.Sw.Info);
		}

        public ICrmInstaller LoadEntityAssembly(string className,string assembly)
        {
            HttpRequest req         =   HttpContext.Current.Request;
            string appPath          =   req.ApplicationPath == "/" ? "" : req.ApplicationPath;

            //Search for assembly in bin dir
            string assemblyName     =   HttpContext.Current.Server.MapPath(appPath + "/bin/" + assembly);
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller LoadEntityAssembly BEG className: {0}, assembly: {1}, assemblyName:{2}",
                    className, assembly, assemblyName),InstallTraceSwitch.Sw.Info);
            // Use reflection for loading assembly
            Assembly a              =   Assembly.LoadFrom(assemblyName);

            // Use reflection for create an installer and Install
            ICrmInstaller Install   =   null;
            try
            {
                Install             =   (ICrmInstaller)a.CreateInstance(className);
            }
            catch (Exception ex)
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller LoadEntityAssembly className: {0}, assembly: {1}, ex: {2}", className, assembly, ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if ( Install == null )
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller LoadEntityAssembly className: {0}, assembly: {1}, null object.", className, assembly);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg);
            }
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller LoadEntityAssembly END className: {0}, assembly: {1}, assemblyName:{2}",
                    className, assembly, assemblyName),InstallTraceSwitch.Sw.Info);
            return Install;
        }

        #region Install CRM access groups in DB 

        /// <summary>
        /// Install the Addon Nice DB access for Crm Server Groups 
        /// </summary>
        public void InstallCrmGroupsInDB()
		{
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine("[V]CrmInstaller InstallCrmGroupsInDB BEG.",InstallTraceSwitch.Sw.Info);
            try
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmGroupsInDB CrmVersion: {0}", newWrapper.CrmVersion),InstallTraceSwitch.Sw.Info);
                string title                            =   LocalizeHelper.Localize("INSTALLCRM_GROUPS_IN_DB", "Granting rigths to Crm Groups in Addon Nice DB");
                SetUpdateProgress(title, 1);
                // Grant access
                string SqlAccessGroupName               =   newWrapper.SqlAccessGroupName;
                string ReportingGroupName               =   newWrapper.ReportingGroupName;
                CrmManDB.GrantAccess(SqlAccessGroupName,"db_owner");
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmGroupsInDB SqlAccessGroupName: {0}", SqlAccessGroupName),InstallTraceSwitch.Sw.Info);
                CrmManDB.GrantAccess(ReportingGroupName,"db_owner");
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmGroupsInDB ReportingGroupName: {0}", ReportingGroupName),InstallTraceSwitch.Sw.Info);
            }
            catch(CancelProgressException )
            {
                if (InstallTraceSwitch.Sw.TraceVerbose)
                    Trace2.WriteLine( "[V]CrmInstaller InstallCrmGroupsInDB install cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError                                   =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
	        catch (Exception ex)
	        {
                string msg                              =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallCrmGroupsInDB ex: {0}",ex);
		        if (InstallTraceSwitch.Sw.TraceError)
                    Trace2.WriteLine(msg,InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("INSTALLCRM_PORTAL_IN_GRPERR","Error installing Crm Groups in Addon Nice DB.");
                throw new CrmInstallException(msg,ex);
	        }
        }

        #endregion Install CRM access groups in DB 

        #region Install Addon Nice Menu in CRM

        /// <summary>
        /// Use the already installed DBCrmServer to get the CrmServerID and install the AddonNice menu
        /// </summary>
        public void InstallPortal(int portalId,bool isMain)
        {
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallPortal BEG  portalId: {0}",portalId),InstallTraceSwitch.Sw.Info);
            InstallPortal(portalId,srvObj.CrmServerId,isMain);
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallPortal END  portalId: {0}",portalId),InstallTraceSwitch.Sw.Info);
        }

        public void InstallPortal(int portalId,int CrmServerId,bool isMain)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallPortal BEG  portalId: {0}, CrmServerId: {1}", portalId,CrmServerId),InstallTraceSwitch.Sw.Info);
            try
            {
                CrmManDB.AddPortalCrmServer(CrmServerId,portalId,isMain);
                InstallAddonNiceMenuInCrm(portalId);
            }
            catch (Exception ex)
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallPortal portalId: {0}, CrmServerId: {1}, ex: {2}", portalId,CrmServerId, ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallPortal END  portalId: {0}, CrmServerId: {1}", portalId,CrmServerId),InstallTraceSwitch.Sw.Info);
        }
        
        public void InstallAddonNiceMenuInCrm(int PortalId)
		{
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallAddonNiceMenuInCrm BEG PortalId: {0}.",PortalId),InstallTraceSwitch.Sw.Info);
            SqlDataReader   dr          =   null;
            try
            {

                dr                      =   new PortalsDB().GetPortal(PortalId);
                if ( !dr.Read() )
                {
                    string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallAddonNiceMenuInCrm Portal not installed PortalId: {0}",PortalId);
                    if ( InstallTraceSwitch.Sw.TraceError )
                        Trace2.WriteLine(msg,InstallTraceSwitch.Sw.Info);
                    throw new Exception(msg);
                }

                string PortalAlias      =   (string)dr["PortalAlias"];

                string title            =   LocalizeHelper.Localize("INSTALLCRM_PORTAL_IN_CRM","Creating the Addon Nice Section in Crm SiteMap");
                SetUpdateProgress(title,1);
                CrmUtil4SiteMap util    =   new CrmUtil4SiteMap(newWrapper);
                ImportExportXml impExp  =   util.Init();

                string prevAreaId       =   "Workplace";
                string langCode         =   System.Threading.Thread.CurrentThread.CurrentCulture.LCID.ToString();

                string nArea            =   NewArea(StStr.Area_AddonNice,langCode,"Addon Nice","Addon Nice extensions");

                title                   =   LocalizeHelper.Localize("INSTALLCRM_ADDONNICE_AREA","Adding Addon Nice Area to Crm");
                SetUpdateProgress(title,1);
                if ( InstallTraceSwitch.Sw.TraceVerbose )
                    Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller NewArea nArea: {0}.",nArea),InstallTraceSwitch.Sw.Info);
                util.AddNewAreaNoImport(prevAreaId,nArea,StStr.Area_AddonNice);
                title                   =   LocalizeHelper.Localize("INSTALLCRM_ADDONNICE_GROUP","Adding Addon Nice Group to Crm");
                SetUpdateProgress(title,1);
                string nGroup           =   NewGroup(StStr.Group_AddonNice,langCode,"Addon Nice","Addon Nice extensions",false);
                util.AddNewGroupNoImport(StStr.Area_AddonNice,string.Empty,nGroup,StStr.Group_AddonNice);
                title                   =   LocalizeHelper.Localize("INSTALLCRM_ADDONNICE_SUBAREA","Adding Addon Nice SubArea to Crm");
                SetUpdateProgress(title,1);
                string url              =   HttpUrlBuilder.BuildPortalUrl(PortalAlias,StStr.PageIDNotAssigned);
                string nSubArea         =   NewSubArea("adn_addonnice",0,url,langCode,"Addon Nice Admin",false,"Web");
                util.AddNewSubAreaNoImport(StStr.Area_AddonNice,StStr.Group_AddonNice,string.Empty,nSubArea,"adn_addonnice");
                util.Save(impExp,true);
                nbInstalled++;
            }
            catch ( CancelProgressException )
            {
                if ( InstallTraceSwitch.Sw.TraceVerbose )
                    Trace2.WriteLine("[V]CrmInstaller InstallAddonNiceMenuInCrm install cancelled by user.",InstallTraceSwitch.Sw.Info);
                lastError               =   LocalizeHelper.Localize("PROGRESS_CANCELLED","Install cancelled by user");
                throw;
            }
            catch ( Exception ex )
            {
                string msg                              =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallAddonNiceMenuInCrm ex: {0}",ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace2.WriteLine(msg,InstallTraceSwitch.Sw.Info);
                lastError                               =   LocalizeHelper.Localize("INSTALLCRM_PORTAL_IN_CRMERR","Error installing Addon Nice menu in CRM");
                throw new CrmInstallException(msg,ex);
            }
            finally
            {
                if ( dr != null )
                    dr.Close();
            }
        }

        string NewArea(string id,string langCode,string Title,string Description)
        {
            string iconurl  =   HttpUrlBuilder.BuildUrl(string.Format("{0}/portalicon.ico",Config.PortalSpecialImagesPath));
            string str      =   CrmUtil4SiteMap.NewArea(id,langCode,Title,Description,iconurl);
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller NewArea : {0}",str),InstallTraceSwitch.Sw.Info);
            return str;
        }

        string NewGroup(string id,string langCode,string Title,string Description,bool isProfile)
        {
            string str      =   CrmUtil4SiteMap.NewGroup(id,langCode,Title,Description,isProfile);
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller NewGroup : {0}",str),InstallTraceSwitch.Sw.Info);
            return str;
        }

        string NewSubAreaWithReadPrivileges(string id,int PassParam,string url,string langCode,string Title,bool AvailableOffline,List<string> ReadPrivileges,string Client)
        {
            string str      =   CrmUtil4SiteMap.NewSubAreaWithReadPrivileges(id,PassParam,url,langCode,Title,AvailableOffline,ReadPrivileges,Client);
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller NewSubArea : {0}",str),InstallTraceSwitch.Sw.Info);
            return str;
        }

        string NewSubArea(string id,int PassParam,string url,string langCode,string Title,bool AvailableOffline,string Client)
        {
            string str      =   CrmUtil4SiteMap.NewSubArea(id,PassParam,url,langCode,Title,AvailableOffline,Client);
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller NewSubArea : {0}",str),InstallTraceSwitch.Sw.Info);
            return str;
        }

        #endregion Install Addon Nice Menu in CRM

        #region Complete the Crm Entities install by Iframes and Form customisation

        public void InstallCrmUI(int portalId,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmUI BEG  portalId: {0}, MainPortalID: {1}",portalId,srvObj.MainPortalID),InstallTraceSwitch.Sw.Info);
            
            InstallCrmUI(portalId,srvObj.CrmServerId,(srvObj.MainPortalID == portalId),publishCustom,publishSiteMap,publishIsv);;
            if ( InstallTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmUI END  portalId: {0}",portalId),InstallTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Complete the custom entities installation by finalizing the UI with Iframes and Form custom
        /// </summary>
        public void InstallCrmUI(int portalId,int CrmServerId,bool isMainPortal,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmUI BEG  portalId: {0}, CrmServerId: {1}, isMainPortal: {2}, Installers.Count: {3}.", 
                    portalId,CrmServerId,isMainPortal,Installers.Count),InstallTraceSwitch.Sw.Info);
            try
            {
                SetTotSteps(Installers.Count+1,1);
                foreach ( string schemaName in Installers.Keys )
                {
                    InstallPack pck    =   Installers[schemaName];
                    InstallCrmEntityUI(schemaName,portalId,isMainPortal,pck.dynEnt,pck.Installer,StateSaver,publishCustom,publishSiteMap,publishIsv);
                }
            }
            catch(CrmInstallException)
            {
                throw;
            }
            catch (Exception ex)
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallCrmUI portalId: {0}, CrmServerId: {1}, ex: {2}", portalId,CrmServerId, ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmUI END  portalId: {0}, CrmServerId: {1}", portalId,CrmServerId),InstallTraceSwitch.Sw.Info);
        }

        /// <summary>
        /// Complete a custom entity installation in CrmServer by finalizing the UI with Iframes and Form custom
        /// </summary>
        public void InstallCrmEntityUI(string schemaName,int portalId,bool isMainPortal,DynEntity dyn,ICrmInstaller installer,IDictionary stateSaver,bool publishCustom,bool publishSiteMap,bool publishIsv)
        {
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmEntityUI BEG  portalId: {0}, SchemaName: {1}, isMainPortal: {2}", 
                    portalId,dyn.SchemaName,isMainPortal),InstallTraceSwitch.Sw.Info);
            try
            {
                    string fmt        =   LocalizeHelper.Localize("INSTALLCRM_ENTITYUI","Installing Crm UI for entity {0} in Portal ID: {1}");
                    string title      =   string.Format(fmt,schemaName,portalId);
                    SetUpdateProgress(title,1);
                    if ( installer.InstallInCrmServer(portalId,isMainPortal,stateSaver,newWrapper,dyn,publishCustom,publishSiteMap,publishIsv) )
                        nbInstalled++;
            }
            catch (Exception ex)
            {
                string msg          =   string.Format(CultureInfo.InvariantCulture,"[E]CrmInstaller InstallCrmEntityUI portalId: {0}, SchemaName: {1}, ex: {2}", portalId,dyn.SchemaName, ex);
                if ( InstallTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,InstallTraceSwitch.Sw.Info);
                string fmt          =   LocalizeHelper.Localize("INSTALLCRM_ENTITYUIERR","Error installing Crm UI for entity {0} in Portal ID: {1}");
                lastError           =   string.Format(fmt,schemaName,portalId);
                throw new CrmInstallException(msg,ex);
            }
            if (InstallTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CrmInstaller InstallCrmUI END  portalId: {0}, SchemaName: {1}", portalId,dyn.SchemaName),InstallTraceSwitch.Sw.Info);
        }

        #endregion Complete the Crm Entities install by Iframes and Form customisation
    }
}